# ----------------------------------------------------------------------------
#       Copyright (C) 2013-2014 Huynh Vi Lam  <domovilam@gmail.com>
#
#       This file is part of pimucha.
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#	
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#	
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------------

import logging,time
from piHAlibs import (confgetval,debug,log2console,log2file,printer)
from piHAparsers import (Decoders,DecoderNames,Parsers)
from .corelibs import (chkparsdaemon)
from .servers import (SetupDaemons)

logger = logging.getLogger()

PARREJECTED = confgetval('pimucha.conf','FilesPath','PARREJECTED','parser_rejected.log')
DECREJECTED = confgetval('pimucha.conf','FilesPath','DECREJECTED','decoder_rejected.log')
RAWEVT = confgetval('pimucha.conf','FilesPath','RAWEVT','rawevt.log')


def str2fargs(param):
    p = param.upper()
    if p == 'NONE': return None
    elif p == 'PARREJECTED': return log2file(PARREJECTED)
    elif p == 'DECREJECTED': return log2file(DECREJECTED)
    elif p == 'NEWIDS': return True
    elif p == 'LOGRAWEVT': return log2file(RAWEVT,'|')


def chkparsdecoder(params,mctrx=None):
    # params = [name:ctrl,decname(largs)]
    p0 = chkparsdaemon(params[0],SetupDaemons)
    if not p0:
        return None
    dev,name,ctrl = p0
    if ctrl[0] == 'N': ctrl = ctrl[1:]
    if mctrx:
        dev = mctrx
    else:
        parser = ctrl + '-PARSER' 
        if parser not in dev.featurenames:
            logger.error('Parser Controller not yet setup %s',parser)
            return None
    p1 = params[1].split('(')
    decname = p1[0]
    if decname not in DecoderNames:
        logger.error('Decoder unknown or not implemented %s',decname)
        return None
    if len(p1) == 1: 
        largs = None
    else:
        largs = '(' + p1[1]
    return dev,name,ctrl,decname,largs


def addparser(params,mctrx=None):
    """
    Add PARSER feature for controller
    params = [name:ctrl(,parserrejected)]
    """
    p0 = chkparsdaemon(params[0],SetupDaemons)
    if not p0:
        return False
    dev,name,ctrl = p0
    if ctrl[0] == 'N': ctrl = ctrl[1:]
    if mctrx: dev = mctrx
    parsername = ctrl + '-PARSER'
    dev.featurenames.append(parsername)
    args = [dev.decoders]
    if len(params) == 2:
        args.append(str2fargs(params[1]))
    parser = Parsers[ctrl]
    dev.features.append(parser(*args))
    return True


def rmparser(params,mctrx=None):
    """
    Remove PARSER from controller feature list
    Reinit all lists
    params = [name:ctrl]
    """
    p = chkparsdaemon(params[0],SetupDaemons)
    if not p:
        return False
    dev,name,ctrl = p
    if ctrl[0] == 'N': ctrl = ctrl[1:]
    if mctrx: dev = mctrx
    parser = ctrl + '-PARSER' 
    if parser not in dev.featurenames:
        logger.error('Parser Controller not yet setup %s',parser)
        return False
    i = dev.featurenames.index(parser)
    for decoder in dev.decoders:
        decoder.close()		#Close coroutine generator
    dev.decodernames = []
    dev.decoders = []
    dev.features[i].close()		#Close coroutine generator
    dev.features.pop(i)
    dev.featurenames.remove(parser)
    logger.info("Parser %s removed for controller %s",parser,ctrl)
    return True


def adddecoder(params,mctrx=None):
    """
    Add a decoder to PARSER / DECODER feature
    params = [name:ctrl,dargs]
    dargs = DECODER(2arg,3arg,4arg)
    parser = ctrl-PARSER
    largs = (2arg,3arg,4arg)
    1arg = list of dfeatures implicit, ldf = [printer()]
    2arg = second position argument DECREJECTED or NONE
    3arg = third position argument NEWIDS or NONE
    4arg = fourth position argument RAWEVT
    """
    p = chkparsdecoder(params,mctrx)
    if not p:
        return False
    dev,name,ctrl,decname,largs = p
    if ctrl[0] == 'N': ctrl = ctrl[1:]
    if mctrx: dev = mctrx
    if decname in dev.decodernames:
        logger.error('Decoder already setup in the list of controller')
        return False
    if largs:
        dargs = largs.strip('()').split(',')
    else:
        dargs = []
    lnamedf = decname + '-FEATURES'
    ldfn = ['DPRINTER']
    ldfr = [printer()]
    args = [ldfr]
    if len(dargs) > 1:
        for a in dargs:
            args.append(str2fargs(a))
    logger.debug('Arguments for decoder %s',repr(args))
    decoder = DecoderNames[decname]
    if (not mctrx) and (decoder not in Decoders[ctrl]):
        logger.error('Decoder %s not implemented for the controller %s',decname,ctrl)
        return False
    try:
        fct = decoder(*args)
        dev.decoders.append(fct)
        dev.decodernames.append(decname)
        dev.dfeatures.append((ldfn,ldfr))
        dev.dfeaturenames.append(lnamedf)
        logger.info('Decoders setup %s for controller',repr(dev.decoders))
        return True
    except Exception as e:
        logger.error("%s : %s", repr(e.__class__), str(e))
        logger.error("In adding decoder %s to server %s" ,decname,dev.name)
        return False


def rmdecoder(params,mctrx=None):
    """
    remove a decoder from PARSER / DECODER feature
    params = [name:ctrl,DECODER]
    parser = ctrl-PARSER
    """
    p = chkparsdecoder(params)
    if not p:
        return False
    dev,name,ctrl,decname,dargs = p
    if mctrx: dev = mctrx
    if decname not in dev.decodernames:
        logger.error("Decoder %s not in server decoders list %s",decname,repr(dev.decodernames))
        return False
    lnamedf = decname + '-FEATURES'
    if lnamedf in dev.decodernames:
        i = dev.decodernames.index(lnamedf)
        ldfn,ldfr = dev.decoders[i]
        for f in ldfr:
            f.close()
        dev.decoders.pop(i)
        dev.decodernames.remove(lnamedf)
    if decname in  dev.decodernames:
        i = dev.decodernames.index(decname)
        dev.decoders[i].close()
        dev.decoders.pop(i)
        dev.decodernames.remove(decname)
        logger.info("Decoder %s removed for controller %s",decname,ctrl)
    else:
        logger.info("Decoder %s already removed from controller %s",decname,ctrl)
    return True
